home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2017 October / PCgo 10-2017 CD-ROM Germany.iso / nw.pak / Unnamed File 004871.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  21.7 KB  |  830 lines

  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. define("mojo/public/js/codec", [
  6.   "mojo/public/js/unicode",
  7.   "mojo/public/js/buffer",
  8. ], function(unicode, buffer) {
  9.  
  10.   var kErrorUnsigned = "Passing negative value to unsigned";
  11.   var kErrorArray = "Passing non Array for array type";
  12.   var kErrorString = "Passing non String for string type";
  13.   var kErrorMap = "Passing non Map for map type";
  14.  
  15.   // Memory -------------------------------------------------------------------
  16.  
  17.   var kAlignment = 8;
  18.  
  19.   function align(size) {
  20.     return size + (kAlignment - (size % kAlignment)) % kAlignment;
  21.   }
  22.  
  23.   function isAligned(offset) {
  24.     return offset >= 0 && (offset % kAlignment) === 0;
  25.   }
  26.  
  27.   // Constants ----------------------------------------------------------------
  28.  
  29.   var kArrayHeaderSize = 8;
  30.   var kStructHeaderSize = 8;
  31.   var kMessageHeaderSize = 16;
  32.   var kMessageWithRequestIDHeaderSize = 24;
  33.   var kMapStructPayloadSize = 16;
  34.  
  35.   var kStructHeaderNumBytesOffset = 0;
  36.   var kStructHeaderNumFieldsOffset = 4;
  37.  
  38.   var kEncodedInvalidHandleValue = 0xFFFFFFFF;
  39.  
  40.   // Decoder ------------------------------------------------------------------
  41.  
  42.   function Decoder(buffer, handles, base) {
  43.     this.buffer = buffer;
  44.     this.handles = handles;
  45.     this.base = base;
  46.     this.next = base;
  47.   }
  48.  
  49.   Decoder.prototype.skip = function(offset) {
  50.     this.next += offset;
  51.   };
  52.  
  53.   Decoder.prototype.readInt8 = function() {
  54.     var result = this.buffer.getInt8(this.next);
  55.     this.next += 1;
  56.     return result;
  57.   };
  58.  
  59.   Decoder.prototype.readUint8 = function() {
  60.     var result = this.buffer.getUint8(this.next);
  61.     this.next += 1;
  62.     return result;
  63.   };
  64.  
  65.   Decoder.prototype.readInt16 = function() {
  66.     var result = this.buffer.getInt16(this.next);
  67.     this.next += 2;
  68.     return result;
  69.   };
  70.  
  71.   Decoder.prototype.readUint16 = function() {
  72.     var result = this.buffer.getUint16(this.next);
  73.     this.next += 2;
  74.     return result;
  75.   };
  76.  
  77.   Decoder.prototype.readInt32 = function() {
  78.     var result = this.buffer.getInt32(this.next);
  79.     this.next += 4;
  80.     return result;
  81.   };
  82.  
  83.   Decoder.prototype.readUint32 = function() {
  84.     var result = this.buffer.getUint32(this.next);
  85.     this.next += 4;
  86.     return result;
  87.   };
  88.  
  89.   Decoder.prototype.readInt64 = function() {
  90.     var result = this.buffer.getInt64(this.next);
  91.     this.next += 8;
  92.     return result;
  93.   };
  94.  
  95.   Decoder.prototype.readUint64 = function() {
  96.     var result = this.buffer.getUint64(this.next);
  97.     this.next += 8;
  98.     return result;
  99.   };
  100.  
  101.   Decoder.prototype.readFloat = function() {
  102.     var result = this.buffer.getFloat32(this.next);
  103.     this.next += 4;
  104.     return result;
  105.   };
  106.  
  107.   Decoder.prototype.readDouble = function() {
  108.     var result = this.buffer.getFloat64(this.next);
  109.     this.next += 8;
  110.     return result;
  111.   };
  112.  
  113.   Decoder.prototype.decodePointer = function() {
  114.     // TODO(abarth): To correctly decode a pointer, we need to know the real
  115.     // base address of the array buffer.
  116.     var offsetPointer = this.next;
  117.     var offset = this.readUint64();
  118.     if (!offset)
  119.       return 0;
  120.     return offsetPointer + offset;
  121.   };
  122.  
  123.   Decoder.prototype.decodeAndCreateDecoder = function(pointer) {
  124.     return new Decoder(this.buffer, this.handles, pointer);
  125.   };
  126.  
  127.   Decoder.prototype.decodeHandle = function() {
  128.     return this.handles[this.readUint32()];
  129.   };
  130.  
  131.   Decoder.prototype.decodeString = function() {
  132.     var numberOfBytes = this.readUint32();
  133.     var numberOfElements = this.readUint32();
  134.     var base = this.next;
  135.     this.next += numberOfElements;
  136.     return unicode.decodeUtf8String(
  137.         new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements));
  138.   };
  139.  
  140.   Decoder.prototype.decodeArray = function(cls) {
  141.     var numberOfBytes = this.readUint32();
  142.     var numberOfElements = this.readUint32();
  143.     var val = new Array(numberOfElements);
  144.     if (cls === PackedBool) {
  145.       var byte;
  146.       for (var i = 0; i < numberOfElements; ++i) {
  147.         if (i % 8 === 0)
  148.           byte = this.readUint8();
  149.         val[i] = (byte & (1 << i % 8)) ? true : false;
  150.       }
  151.     } else {
  152.       for (var i = 0; i < numberOfElements; ++i) {
  153.         val[i] = cls.decode(this);
  154.       }
  155.     }
  156.     return val;
  157.   };
  158.  
  159.   Decoder.prototype.decodeStruct = function(cls) {
  160.     return cls.decode(this);
  161.   };
  162.  
  163.   Decoder.prototype.decodeStructPointer = function(cls) {
  164.     var pointer = this.decodePointer();
  165.     if (!pointer) {
  166.       return null;
  167.     }
  168.     return cls.decode(this.decodeAndCreateDecoder(pointer));
  169.   };
  170.  
  171.   Decoder.prototype.decodeArrayPointer = function(cls) {
  172.     var pointer = this.decodePointer();
  173.     if (!pointer) {
  174.       return null;
  175.     }
  176.     return this.decodeAndCreateDecoder(pointer).decodeArray(cls);
  177.   };
  178.  
  179.   Decoder.prototype.decodeStringPointer = function() {
  180.     var pointer = this.decodePointer();
  181.     if (!pointer) {
  182.       return null;
  183.     }
  184.     return this.decodeAndCreateDecoder(pointer).decodeString();
  185.   };
  186.  
  187.   Decoder.prototype.decodeMap = function(keyClass, valueClass) {
  188.     this.skip(4); // numberOfBytes
  189.     this.skip(4); // numberOfFields
  190.     var keys = this.decodeArrayPointer(keyClass);
  191.     var values = this.decodeArrayPointer(valueClass);
  192.     var val = new Map();
  193.     for (var i = 0; i < keys.length; i++)
  194.       val.set(keys[i], values[i]);
  195.     return val;
  196.   };
  197.  
  198.   Decoder.prototype.decodeMapPointer = function(keyClass, valueClass) {
  199.     var pointer = this.decodePointer();
  200.     if (!pointer) {
  201.       return null;
  202.     }
  203.     var decoder = this.decodeAndCreateDecoder(pointer);
  204.     return decoder.decodeMap(keyClass, valueClass);
  205.   };
  206.  
  207.   // Encoder ------------------------------------------------------------------
  208.  
  209.   function Encoder(buffer, handles, base) {
  210.     this.buffer = buffer;
  211.     this.handles = handles;
  212.     this.base = base;
  213.     this.next = base;
  214.   }
  215.  
  216.   Encoder.prototype.skip = function(offset) {
  217.     this.next += offset;
  218.   };
  219.  
  220.   Encoder.prototype.writeInt8 = function(val) {
  221.     this.buffer.setInt8(this.next, val);
  222.     this.next += 1;
  223.   };
  224.  
  225.   Encoder.prototype.writeUint8 = function(val) {
  226.     if (val < 0) {
  227.       throw new Error(kErrorUnsigned);
  228.     }
  229.     this.buffer.setUint8(this.next, val);
  230.     this.next += 1;
  231.   };
  232.  
  233.   Encoder.prototype.writeInt16 = function(val) {
  234.     this.buffer.setInt16(this.next, val);
  235.     this.next += 2;
  236.   };
  237.  
  238.   Encoder.prototype.writeUint16 = function(val) {
  239.     if (val < 0) {
  240.       throw new Error(kErrorUnsigned);
  241.     }
  242.     this.buffer.setUint16(this.next, val);
  243.     this.next += 2;
  244.   };
  245.  
  246.   Encoder.prototype.writeInt32 = function(val) {
  247.     this.buffer.setInt32(this.next, val);
  248.     this.next += 4;
  249.   };
  250.  
  251.   Encoder.prototype.writeUint32 = function(val) {
  252.     if (val < 0) {
  253.       throw new Error(kErrorUnsigned);
  254.     }
  255.     this.buffer.setUint32(this.next, val);
  256.     this.next += 4;
  257.   };
  258.  
  259.   Encoder.prototype.writeInt64 = function(val) {
  260.     this.buffer.setInt64(this.next, val);
  261.     this.next += 8;
  262.   };
  263.  
  264.   Encoder.prototype.writeUint64 = function(val) {
  265.     if (val < 0) {
  266.       throw new Error(kErrorUnsigned);
  267.     }
  268.     this.buffer.setUint64(this.next, val);
  269.     this.next += 8;
  270.   };
  271.  
  272.   Encoder.prototype.writeFloat = function(val) {
  273.     this.buffer.setFloat32(this.next, val);
  274.     this.next += 4;
  275.   };
  276.  
  277.   Encoder.prototype.writeDouble = function(val) {
  278.     this.buffer.setFloat64(this.next, val);
  279.     this.next += 8;
  280.   };
  281.  
  282.   Encoder.prototype.encodePointer = function(pointer) {
  283.     if (!pointer)
  284.       return this.writeUint64(0);
  285.     // TODO(abarth): To correctly encode a pointer, we need to know the real
  286.     // base address of the array buffer.
  287.     var offset = pointer - this.next;
  288.     this.writeUint64(offset);
  289.   };
  290.  
  291.   Encoder.prototype.createAndEncodeEncoder = function(size) {
  292.     var pointer = this.buffer.alloc(align(size));
  293.     this.encodePointer(pointer);
  294.     return new Encoder(this.buffer, this.handles, pointer);
  295.   };
  296.  
  297.   Encoder.prototype.encodeHandle = function(handle) {
  298.     this.handles.push(handle);
  299.     this.writeUint32(this.handles.length - 1);
  300.   };
  301.  
  302.   Encoder.prototype.encodeString = function(val) {
  303.     var base = this.next + kArrayHeaderSize;
  304.     var numberOfElements = unicode.encodeUtf8String(
  305.         val, new Uint8Array(this.buffer.arrayBuffer, base));
  306.     var numberOfBytes = kArrayHeaderSize + numberOfElements;
  307.     this.writeUint32(numberOfBytes);
  308.     this.writeUint32(numberOfElements);
  309.     this.next += numberOfElements;
  310.   };
  311.  
  312.   Encoder.prototype.encodeArray =
  313.       function(cls, val, numberOfElements, encodedSize) {
  314.     if (numberOfElements === undefined)
  315.       numberOfElements = val.length;
  316.     if (encodedSize === undefined)
  317.       encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements;
  318.  
  319.     this.writeUint32(encodedSize);
  320.     this.writeUint32(numberOfElements);
  321.  
  322.     if (cls === PackedBool) {
  323.       var byte = 0;
  324.       for (i = 0; i < numberOfElements; ++i) {
  325.         if (val[i])
  326.           byte |= (1 << i % 8);
  327.         if (i % 8 === 7 || i == numberOfElements - 1) {
  328.           Uint8.encode(this, byte);
  329.           byte = 0;
  330.         }
  331.       }
  332.     } else {
  333.       for (var i = 0; i < numberOfElements; ++i)
  334.         cls.encode(this, val[i]);
  335.     }
  336.   };
  337.  
  338.   Encoder.prototype.encodeStruct = function(cls, val) {
  339.     return cls.encode(this, val);
  340.   };
  341.  
  342.   Encoder.prototype.encodeStructPointer = function(cls, val) {
  343.     if (val == null) {
  344.       // Also handles undefined, since undefined == null.
  345.       this.encodePointer(val);
  346.       return;
  347.     }
  348.     var encoder = this.createAndEncodeEncoder(cls.encodedSize);
  349.     cls.encode(encoder, val);
  350.   };
  351.  
  352.   Encoder.prototype.encodeArrayPointer = function(cls, val) {
  353.     if (val == null) {
  354.       // Also handles undefined, since undefined == null.
  355.       this.encodePointer(val);
  356.       return;
  357.     }
  358.  
  359.     var numberOfElements = val.length;
  360.     if (!Number.isSafeInteger(numberOfElements) || numberOfElements < 0)
  361.       throw new Error(kErrorArray);
  362.  
  363.     var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ?
  364.         Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements);
  365.     var encoder = this.createAndEncodeEncoder(encodedSize);
  366.     encoder.encodeArray(cls, val, numberOfElements, encodedSize);
  367.   };
  368.  
  369.   Encoder.prototype.encodeStringPointer = function(val) {
  370.     if (val == null) {
  371.       // Also handles undefined, since undefined == null.
  372.       this.encodePointer(val);
  373.       return;
  374.     }
  375.     // Only accepts string primivites, not String Objects like new String("foo")
  376.     if (typeof(val) !== "string") {
  377.       throw new Error(kErrorString);
  378.     }
  379.     var encodedSize = kArrayHeaderSize + unicode.utf8Length(val);
  380.     var encoder = this.createAndEncodeEncoder(encodedSize);
  381.     encoder.encodeString(val);
  382.   };
  383.  
  384.   Encoder.prototype.encodeMap = function(keyClass, valueClass, val) {
  385.     var keys = new Array(val.size);
  386.     var values = new Array(val.size);
  387.     var i = 0;
  388.     val.forEach(function(value, key) {
  389.       values[i] = value;
  390.       keys[i++] = key;
  391.     });
  392.     this.writeUint32(kStructHeaderSize + kMapStructPayloadSize);
  393.     this.writeUint32(2); // two fields: keys, values
  394.     this.encodeArrayPointer(keyClass, keys);
  395.     this.encodeArrayPointer(valueClass, values);
  396.   }
  397.  
  398.   Encoder.prototype.encodeMapPointer = function(keyClass, valueClass, val) {
  399.     if (val == null) {
  400.       // Also handles undefined, since undefined == null.
  401.       this.encodePointer(val);
  402.       return;
  403.     }
  404.     if (!(val instanceof Map)) {
  405.       throw new Error(kErrorMap);
  406.     }
  407.     var encodedSize = kStructHeaderSize + kMapStructPayloadSize;
  408.     var encoder = this.createAndEncodeEncoder(encodedSize);
  409.     encoder.encodeMap(keyClass, valueClass, val);
  410.   };
  411.  
  412.   // Message ------------------------------------------------------------------
  413.  
  414.   var kMessageNameOffset = kStructHeaderSize;
  415.   var kMessageFlagsOffset = kMessageNameOffset + 4;
  416.   var kMessageRequestIDOffset = kMessageFlagsOffset + 4;
  417.  
  418.   var kMessageExpectsResponse = 1 << 0;
  419.   var kMessageIsResponse      = 1 << 1;
  420.  
  421.   function Message(buffer, handles) {
  422.     this.buffer = buffer;
  423.     this.handles = handles;
  424.   }
  425.  
  426.   Message.prototype.getHeaderNumBytes = function() {
  427.     return this.buffer.getUint32(kStructHeaderNumBytesOffset);
  428.   };
  429.  
  430.   Message.prototype.getHeaderNumFields = function() {
  431.     return this.buffer.getUint32(kStructHeaderNumFieldsOffset);
  432.   };
  433.  
  434.   Message.prototype.getName = function() {
  435.     return this.buffer.getUint32(kMessageNameOffset);
  436.   };
  437.  
  438.   Message.prototype.getFlags = function() {
  439.     return this.buffer.getUint32(kMessageFlagsOffset);
  440.   };
  441.  
  442.   Message.prototype.isResponse = function() {
  443.     return (this.getFlags() & kMessageIsResponse) != 0;
  444.   };
  445.  
  446.   Message.prototype.expectsResponse = function() {
  447.     return (this.getFlags() & kMessageExpectsResponse) != 0;
  448.   };
  449.  
  450.   Message.prototype.setRequestID = function(requestID) {
  451.     // TODO(darin): Verify that space was reserved for this field!
  452.     this.buffer.setUint64(kMessageRequestIDOffset, requestID);
  453.   };
  454.  
  455.  
  456.   // MessageBuilder -----------------------------------------------------------
  457.  
  458.   function MessageBuilder(messageName, payloadSize) {
  459.     // Currently, we don't compute the payload size correctly ahead of time.
  460.     // Instead, we resize the buffer at the end.
  461.     var numberOfBytes = kMessageHeaderSize + payloadSize;
  462.     this.buffer = new buffer.Buffer(numberOfBytes);
  463.     this.handles = [];
  464.     var encoder = this.createEncoder(kMessageHeaderSize);
  465.     encoder.writeUint32(kMessageHeaderSize);
  466.     encoder.writeUint32(2);  // num_fields.
  467.     encoder.writeUint32(messageName);
  468.     encoder.writeUint32(0);  // flags.
  469.   }
  470.  
  471.   MessageBuilder.prototype.createEncoder = function(size) {
  472.     var pointer = this.buffer.alloc(size);
  473.     return new Encoder(this.buffer, this.handles, pointer);
  474.   };
  475.  
  476.   MessageBuilder.prototype.encodeStruct = function(cls, val) {
  477.     cls.encode(this.createEncoder(cls.encodedSize), val);
  478.   };
  479.  
  480.   MessageBuilder.prototype.finish = function() {
  481.     // TODO(abarth): Rather than resizing the buffer at the end, we could
  482.     // compute the size we need ahead of time, like we do in C++.
  483.     this.buffer.trim();
  484.     var message = new Message(this.buffer, this.handles);
  485.     this.buffer = null;
  486.     this.handles = null;
  487.     this.encoder = null;
  488.     return message;
  489.   };
  490.  
  491.   // MessageWithRequestIDBuilder -----------------------------------------------
  492.  
  493.   function MessageWithRequestIDBuilder(messageName, payloadSize, flags,
  494.                                        requestID) {
  495.     // Currently, we don't compute the payload size correctly ahead of time.
  496.     // Instead, we resize the buffer at the end.
  497.     var numberOfBytes = kMessageWithRequestIDHeaderSize + payloadSize;
  498.     this.buffer = new buffer.Buffer(numberOfBytes);
  499.     this.handles = [];
  500.     var encoder = this.createEncoder(kMessageWithRequestIDHeaderSize);
  501.     encoder.writeUint32(kMessageWithRequestIDHeaderSize);
  502.     encoder.writeUint32(3);  // num_fields.
  503.     encoder.writeUint32(messageName);
  504.     encoder.writeUint32(flags);
  505.     encoder.writeUint64(requestID);
  506.   }
  507.  
  508.   MessageWithRequestIDBuilder.prototype =
  509.       Object.create(MessageBuilder.prototype);
  510.  
  511.   MessageWithRequestIDBuilder.prototype.constructor =
  512.       MessageWithRequestIDBuilder;
  513.  
  514.   // MessageReader ------------------------------------------------------------
  515.  
  516.   function MessageReader(message) {
  517.     this.decoder = new Decoder(message.buffer, message.handles, 0);
  518.     var messageHeaderSize = this.decoder.readUint32();
  519.     this.payloadSize = message.buffer.byteLength - messageHeaderSize;
  520.     var numFields = this.decoder.readUint32();
  521.     this.messageName = this.decoder.readUint32();
  522.     this.flags = this.decoder.readUint32();
  523.     if (numFields >= 3)
  524.       this.requestID = this.decoder.readUint64();
  525.     this.decoder.skip(messageHeaderSize - this.decoder.next);
  526.   }
  527.  
  528.   MessageReader.prototype.decodeStruct = function(cls) {
  529.     return cls.decode(this.decoder);
  530.   };
  531.  
  532.   // Built-in types -----------------------------------------------------------
  533.  
  534.   // This type is only used with ArrayOf(PackedBool).
  535.   function PackedBool() {
  536.   }
  537.  
  538.   function Int8() {
  539.   }
  540.  
  541.   Int8.encodedSize = 1;
  542.  
  543.   Int8.decode = function(decoder) {
  544.     return decoder.readInt8();
  545.   };
  546.  
  547.   Int8.encode = function(encoder, val) {
  548.     encoder.writeInt8(val);
  549.   };
  550.  
  551.   Uint8.encode = function(encoder, val) {
  552.     encoder.writeUint8(val);
  553.   };
  554.  
  555.   function Uint8() {
  556.   }
  557.  
  558.   Uint8.encodedSize = 1;
  559.  
  560.   Uint8.decode = function(decoder) {
  561.     return decoder.readUint8();
  562.   };
  563.  
  564.   Uint8.encode = function(encoder, val) {
  565.     encoder.writeUint8(val);
  566.   };
  567.  
  568.   function Int16() {
  569.   }
  570.  
  571.   Int16.encodedSize = 2;
  572.  
  573.   Int16.decode = function(decoder) {
  574.     return decoder.readInt16();
  575.   };
  576.  
  577.   Int16.encode = function(encoder, val) {
  578.     encoder.writeInt16(val);
  579.   };
  580.  
  581.   function Uint16() {
  582.   }
  583.  
  584.   Uint16.encodedSize = 2;
  585.  
  586.   Uint16.decode = function(decoder) {
  587.     return decoder.readUint16();
  588.   };
  589.  
  590.   Uint16.encode = function(encoder, val) {
  591.     encoder.writeUint16(val);
  592.   };
  593.  
  594.   function Int32() {
  595.   }
  596.  
  597.   Int32.encodedSize = 4;
  598.  
  599.   Int32.decode = function(decoder) {
  600.     return decoder.readInt32();
  601.   };
  602.  
  603.   Int32.encode = function(encoder, val) {
  604.     encoder.writeInt32(val);
  605.   };
  606.  
  607.   function Uint32() {
  608.   }
  609.  
  610.   Uint32.encodedSize = 4;
  611.  
  612.   Uint32.decode = function(decoder) {
  613.     return decoder.readUint32();
  614.   };
  615.  
  616.   Uint32.encode = function(encoder, val) {
  617.     encoder.writeUint32(val);
  618.   };
  619.  
  620.   function Int64() {
  621.   }
  622.  
  623.   Int64.encodedSize = 8;
  624.  
  625.   Int64.decode = function(decoder) {
  626.     return decoder.readInt64();
  627.   };
  628.  
  629.   Int64.encode = function(encoder, val) {
  630.     encoder.writeInt64(val);
  631.   };
  632.  
  633.   function Uint64() {
  634.   }
  635.  
  636.   Uint64.encodedSize = 8;
  637.  
  638.   Uint64.decode = function(decoder) {
  639.     return decoder.readUint64();
  640.   };
  641.  
  642.   Uint64.encode = function(encoder, val) {
  643.     encoder.writeUint64(val);
  644.   };
  645.  
  646.   function String() {
  647.   };
  648.  
  649.   String.encodedSize = 8;
  650.  
  651.   String.decode = function(decoder) {
  652.     return decoder.decodeStringPointer();
  653.   };
  654.  
  655.   String.encode = function(encoder, val) {
  656.     encoder.encodeStringPointer(val);
  657.   };
  658.  
  659.   function NullableString() {
  660.   }
  661.  
  662.   NullableString.encodedSize = String.encodedSize;
  663.  
  664.   NullableString.decode = String.decode;
  665.  
  666.   NullableString.encode = String.encode;
  667.  
  668.   function Float() {
  669.   }
  670.  
  671.   Float.encodedSize = 4;
  672.  
  673.   Float.decode = function(decoder) {
  674.     return decoder.readFloat();
  675.   };
  676.  
  677.   Float.encode = function(encoder, val) {
  678.     encoder.writeFloat(val);
  679.   };
  680.  
  681.   function Double() {
  682.   }
  683.  
  684.   Double.encodedSize = 8;
  685.  
  686.   Double.decode = function(decoder) {
  687.     return decoder.readDouble();
  688.   };
  689.  
  690.   Double.encode = function(encoder, val) {
  691.     encoder.writeDouble(val);
  692.   };
  693.  
  694.   function PointerTo(cls) {
  695.     this.cls = cls;
  696.   }
  697.  
  698.   PointerTo.prototype.encodedSize = 8;
  699.  
  700.   PointerTo.prototype.decode = function(decoder) {
  701.     var pointer = decoder.decodePointer();
  702.     if (!pointer) {
  703.       return null;
  704.     }
  705.     return this.cls.decode(decoder.decodeAndCreateDecoder(pointer));
  706.   };
  707.  
  708.   PointerTo.prototype.encode = function(encoder, val) {
  709.     if (!val) {
  710.       encoder.encodePointer(val);
  711.       return;
  712.     }
  713.     var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
  714.     this.cls.encode(objectEncoder, val);
  715.   };
  716.  
  717.   function NullablePointerTo(cls) {
  718.     PointerTo.call(this, cls);
  719.   }
  720.  
  721.   NullablePointerTo.prototype = Object.create(PointerTo.prototype);
  722.  
  723.   function ArrayOf(cls, length) {
  724.     this.cls = cls;
  725.     this.length = length || 0;
  726.   }
  727.  
  728.   ArrayOf.prototype.encodedSize = 8;
  729.  
  730.   ArrayOf.prototype.dimensions = function() {
  731.     return [this.length].concat(
  732.       (this.cls instanceof ArrayOf) ? this.cls.dimensions() : []);
  733.   }
  734.  
  735.   ArrayOf.prototype.decode = function(decoder) {
  736.     return decoder.decodeArrayPointer(this.cls);
  737.   };
  738.  
  739.   ArrayOf.prototype.encode = function(encoder, val) {
  740.     encoder.encodeArrayPointer(this.cls, val);
  741.   };
  742.  
  743.   function NullableArrayOf(cls) {
  744.     ArrayOf.call(this, cls);
  745.   }
  746.  
  747.   NullableArrayOf.prototype = Object.create(ArrayOf.prototype);
  748.  
  749.   function Handle() {
  750.   }
  751.  
  752.   Handle.encodedSize = 4;
  753.  
  754.   Handle.decode = function(decoder) {
  755.     return decoder.decodeHandle();
  756.   };
  757.  
  758.   Handle.encode = function(encoder, val) {
  759.     encoder.encodeHandle(val);
  760.   };
  761.  
  762.   function NullableHandle() {
  763.   }
  764.  
  765.   NullableHandle.encodedSize = Handle.encodedSize;
  766.  
  767.   NullableHandle.decode = Handle.decode;
  768.  
  769.   NullableHandle.encode = Handle.encode;
  770.  
  771.   function MapOf(keyClass, valueClass) {
  772.     this.keyClass = keyClass;
  773.     this.valueClass = valueClass;
  774.   }
  775.  
  776.   MapOf.prototype.encodedSize = 8;
  777.  
  778.   MapOf.prototype.decode = function(decoder) {
  779.     return decoder.decodeMapPointer(this.keyClass, this.valueClass);
  780.   };
  781.  
  782.   MapOf.prototype.encode = function(encoder, val) {
  783.     encoder.encodeMapPointer(this.keyClass, this.valueClass, val);
  784.   };
  785.  
  786.   function NullableMapOf(keyClass, valueClass) {
  787.     MapOf.call(this, keyClass, valueClass);
  788.   }
  789.  
  790.   NullableMapOf.prototype = Object.create(MapOf.prototype);
  791.  
  792.   var exports = {};
  793.   exports.align = align;
  794.   exports.isAligned = isAligned;
  795.   exports.Message = Message;
  796.   exports.MessageBuilder = MessageBuilder;
  797.   exports.MessageWithRequestIDBuilder = MessageWithRequestIDBuilder;
  798.   exports.MessageReader = MessageReader;
  799.   exports.kArrayHeaderSize = kArrayHeaderSize;
  800.   exports.kMapStructPayloadSize = kMapStructPayloadSize;
  801.   exports.kStructHeaderSize = kStructHeaderSize;
  802.   exports.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue;
  803.   exports.kMessageHeaderSize = kMessageHeaderSize;
  804.   exports.kMessageWithRequestIDHeaderSize = kMessageWithRequestIDHeaderSize;
  805.   exports.kMessageExpectsResponse = kMessageExpectsResponse;
  806.   exports.kMessageIsResponse = kMessageIsResponse;
  807.   exports.Int8 = Int8;
  808.   exports.Uint8 = Uint8;
  809.   exports.Int16 = Int16;
  810.   exports.Uint16 = Uint16;
  811.   exports.Int32 = Int32;
  812.   exports.Uint32 = Uint32;
  813.   exports.Int64 = Int64;
  814.   exports.Uint64 = Uint64;
  815.   exports.Float = Float;
  816.   exports.Double = Double;
  817.   exports.String = String;
  818.   exports.NullableString = NullableString;
  819.   exports.PointerTo = PointerTo;
  820.   exports.NullablePointerTo = NullablePointerTo;
  821.   exports.ArrayOf = ArrayOf;
  822.   exports.NullableArrayOf = NullableArrayOf;
  823.   exports.PackedBool = PackedBool;
  824.   exports.Handle = Handle;
  825.   exports.NullableHandle = NullableHandle;
  826.   exports.MapOf = MapOf;
  827.   exports.NullableMapOf = NullableMapOf;
  828.   return exports;
  829. });
  830.